

abstract class IView<T> {
  setPresenter(T presenter);
}

abstract class IPresenter {
  init();
}

class Contact {
  final String fullName;

  final String email;

  const Contact({this.fullName, this.email});
}

abstract class ContactRepository {
  Future<List<Contact>> fetch();
}

class MockContactRepository implements ContactRepository {
  @override
  Future<List<Contact>> fetch() {
    return new Future.value(kContacts);
  }

  var kContacts = const <Contact>[
    const Contact(fullName: "Li bai", email: "libai@live.com"),
    const Contact(fullName: "Cheng yaojin", email: "chengyaojin@live.com"),
    const Contact(fullName: "Mi yue", email: "miyue@live.com"),
    const Contact(fullName: "A ke", email: "ake@live.com"),
    const Contact(fullName: "Lu ban", email: "luban@live.com"),
    const Contact(fullName: "Da qiao", email: "daqiao@live.com"),
    const Contact(fullName: "Hou yi", email: "houyi@live.com"),
    const Contact(fullName: "Liu bei", email: "liubei@live.com"),
    const Contact(fullName: "Wang zhaojun", email: "wangzhaoju@live.com"),
  ];
}

abstract class Presenter implements IPresenter {
  loadContacts();
}

abstract class View implements IView<Presenter> {
  void onLoadContactsComplete(List<Contact> itmes);
  void onLoadContactsError();
}

class ContactPresenter implements Presenter {
  View _view;
  ContactRepository _repository;
  ContactPresenter(this._view) {
    _view.setPresenter(this);
  }
  @override
  init() {
    print("---ContactPresenter:init");
    _repository = new MockContactRepository();
  }

  @override
  void loadContacts() {
    assert(_view != null);
    _repository.fetch().then((contacts) {
      _view.onLoadContactsComplete(contacts);
    }).catchError((error) {
      print(error);
      _view.onLoadContactsError();
    });
  }
}
